%{
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "HashSet.h"
#define maxRuleSize 5000
extern int yylineno;
int expand_rules;
int crRuleIndex;
char bodyExpansion[maxRuleSize];
typedef struct StringList StringList;
extern FILE *yyout;
struct StringList
{
 char*name;
 char*term_list;
 int arity;
 StringList *next;
};

struct StringList *Vars,*Predicates,*Atoms_in_body,*VarsInNegativePart,*VarsInPositivePart,*termsWithOperations;
char *unionBodies(char *body1,char*body2)
{
  /* the second body (expanded) or both of the arguments may be empty*/
  if(!body1 && !body2)return 0;
  if(!body2)
  {
     return strdup(body1);
  }
  if(!body1)
  {
     int L2=strlen(body2);
     char *result=(char*)malloc(L2+2);
     int i;
     for(i=0;i<L2;i++)result[i]=body2[i];
     result[L2]='.';
     result[L2+1]='\0';
     return result;
  }

  /* if it is not empty-we need to remove DOT from the end of the first body,
     ,to concatenate both and to add DOT sign to the end of the concatenation.*/
   int L1=strlen(body1);
   int L2=strlen(body2);
   char *result=(char*)malloc(L1+L2+2);
   int idx;
   for(idx=0;idx<L1;idx++)
   {
      result[idx]=body1[idx];
   }
   for(idx=L1;idx<L1+L2;idx++)
   {
     result[idx]=body2[idx-L1];
   }
   result[L1-1]=',';
   result[L1+L2]='.';
   result[L1+L2+1]='\0';
   return result;
}

char *removeReplacers(char *s)
{

  int idx=0;
  int L=strlen(s);
  int countDollars=0;
  for(;idx<L;idx++)
  {
   if(s[idx]=='$')countDollars++;
  }
  idx=0;
  char*result=(char*)malloc(L+countDollars+1);
  int resultIdx=0;
  while(idx<L)
  {
    if(s[idx]!='$')
    {
      result[resultIdx++]=s[idx];
      ++idx;
    }
    else
    {
       result[resultIdx++]='V';
       result[resultIdx++]='A';
       result[resultIdx++]='R';
       result[resultIdx++]='_';
       ++idx;
       while(s[idx]!='$')
       {
         result[resultIdx++]=s[idx++];
       }
       ++idx;

    }
  }
  result[resultIdx]='\0';
  return result;

}
int getDigitsCount(int n)
{
 /*returns the number of digits in n*/
 int count=0;
 if(n==0)return 1;
 while(n>0)
 {
  ++count;
  n/=10;
 }
 return count;
}
int getListLength(StringList *L)
{
  if(L==0)return 0;
  int length=0;
  do
  {
    ++length;
  }while(L=L->next);
  return length;
}

char** getUniqueVariableNames(StringList *ExistingVars,int countNeeded)
{
  if(countNeeded==0)return 0;
  char** result=malloc(countNeeded*sizeof(char*));
  int i;

  int count=getListLength(Vars);
  int digits=getDigitsCount(count);
  for(i=0;i<countNeeded;i++)
  {
    result[i]=(char*)malloc(6+digits);
    int j;
    for(j=0;j<6+digits;j++)result[i][j]='\0';
    strcpy(result[i],"VAR_");
  }

  int varnumber=0;
  for(i=0;i<countNeeded;i++)
  {
    do
    {
      sprintf(result[i]+4,"%d",varnumber);
      varnumber++;
    }while(stringInList(result[i],ExistingVars));
  }
  return result;
}

char *getATermsDeclaration(char **VarNames,int count)
{
  int length=0;
  if(count==0)return 0;
  StringList *TermsCopy=termsWithOperations;
  int i;
  for(i=0;i<count;i++)
  {
    length+=strlen(VarNames[i]);
    length+=strlen(TermsCopy->name);
    ++length;/*for equal sign*/;
    if(i!=0)++length;/* for comma*/
    TermsCopy=TermsCopy->next;
  }
  char*result=(char*)malloc(length+2);
  for(i=0;i<length+2;i++)result[i]='\0';
  int curIndex=0;
  for(i=0;i<count;i++)
  {
    if(i!=0)
    {
      sprintf(result+curIndex,",");
     ++curIndex;
    }
    sprintf(result+curIndex,"%s",VarNames[i]);
    curIndex+=strlen(VarNames[i]);
    sprintf(result+curIndex,"=");
    ++curIndex;
    sprintf(result+curIndex,"%s",termsWithOperations->name);
    curIndex+=strlen(termsWithOperations->name);
    termsWithOperations=termsWithOperations->next;
   }
   result[curIndex]='\0';
   return result;
}


char *getOutputFile(char *inputFileName)
{
  int L=strlen(inputFileName);
  int lastDotIndex=-1;
  int idx;
  for(idx=0;idx<L;idx++)
  {
    if(inputFileName[idx]=='.')lastDotIndex=idx;
  }
  char *outputFileName=(char*)malloc(strlen(inputFileName)+5);
  if(lastDotIndex!=-1)L=lastDotIndex;
  int i;
  for(i=0;i<L;i++)outputFileName[i]=inputFileName[i];
  outputFileName[L]='.';
  outputFileName[L+1]='a';
  outputFileName[L+2]='s';
  outputFileName[L+3]='p';
  outputFileName[L+4]='\0';
  return outputFileName;
}

char *concat3(char *str1,char *str2,char *str3)
{
    /*concatenate three strings and frees the memory allocated for substrings before*/
    /* returns a pointer to the new string*/

    int L=strlen(str1)+strlen(str2)+strlen(str3);
    char *s=(char*)malloc(L+2);
    sprintf(s,"%s%s%s",str1,str2,str3);
    free(str1);
    free(str2);
    free(str3);
    return s;
}
struct NameList* SplitList(char *name_sequence,int countBrackets)
{
  struct NameList *snl=(struct NameList*) malloc(sizeof(struct NameList));
  int leng=strlen(name_sequence);
  int arity=1;
  int i;
  int openBrackets=0;
  for(i=0;i<leng;i++)
  {
   if(countBrackets && name_sequence[i]=='(')++openBrackets;
   if(countBrackets && name_sequence[i]==')')--openBrackets;
   if(name_sequence[i]==',' && (!countBrackets || !openBrackets) )++arity;
  }
  snl->L=(struct Name*)malloc(arity*sizeof(struct Name));
  snl->arity=arity;
  char *curstr=(char*)malloc(leng+1);
  char *saveptr=curstr;
  int count=0;  /* how many sort names were found*/
  openBrackets=0;
  do
  {
   if(countBrackets && *name_sequence =='(')++openBrackets;
   if(countBrackets && *name_sequence ==')')--openBrackets;
   if(*(name_sequence+1)=='\0')*curstr++=*name_sequence;
   if((*name_sequence==',' || *(name_sequence+1)=='\0')
      && (!countBrackets || !openBrackets))
   {
      *curstr='\0';
      snl->L[count].name=strdup(saveptr);
      snl->L[count++].flag=strcmp(saveptr,"nat");
      curstr=saveptr;
   }
   else
   {
      *curstr++=*name_sequence;
   }
  }while(*(++name_sequence));

  return snl;
}

void addToListUniq(struct StringList **L,struct StringList *prev,char *newName)
{
  /* adds newName to StringList. Does not allow dublicates*/
  /* prev is the pointer to the last object in list,after which we want to add new name*/
  /* call the function with prev=0 if you want the checker of uniqueness to start from the firsst element*/

  if(!(*L))
  {
    (*L)=(struct StringList*)malloc(sizeof (struct StringList));
    (*L)->name=strdup(newName);
    (*L)->arity=0;
    (*L)->term_list=0;
    (*L)->next=0;
    if(prev)
    {
       prev->next=(*L);
    }
    return;
  }
  if((*L)->name && !strcmp((*L)->name,newName))return;
  addToListUniq(&((*L)->next),(*L),newName);
}

void clearList(struct StringList **L)
{
  if(!(*L))return;
  if((*L)->next)
  {
    clearList(&((*L)->next));
  }
  if((*L)->name)free((*L)->name);
  free(*L);
  *L=0;
}

char* getExpandedBody()
{
  if(!Predicates)return 0;
  clearList(&Atoms_in_body);
  do
  {
    NameList* names=getSortListByName(Predicates->name);
    if(names==0)
    {
      yyerror("predicate %s was not declared",Predicates->name);
      exit(0);
    }
    /* the names of the sorts,which are the arguments of the predicates!!!!!!!!!!!!!!"*/
    int name_list_arity=names->arity;
    NameList* terms=SplitList(Predicates->term_list,1);
    /* if the arities are not the same -the error is produced!*/
    /* added in version 1.09*/
    if(names->arity != terms->arity)
    {
        yyerror("predicate %s with arity %d was not declared",Predicates->name,terms->arity);
        exit(0);
    }
    int i;

    for( i=0;i<name_list_arity;i++)
    {
      char *op=(char*)malloc(2);
      op[0]='(';op[1]='\0';

      if(!strcmp(names->L[i].name,"nat"))continue;/*built-in sort*/
      char *sort_atom=concat3(strdup(names->L[i].name),op,strdup(terms->L[i].name));
      int sort_atom_l=strlen(sort_atom);
      sort_atom[sort_atom_l]=')';
      sort_atom[sort_atom_l+1]='\0';
      addToListUniq(&Atoms_in_body,0,sort_atom);
    }
    struct Predicates *nextPointer=Predicates->next;
    if(Predicates->name)free(Predicates->name);
    if(Predicates->term_list)free(Predicates->term_list);
    Predicates=nextPointer;
  }while(Predicates);
  if(!Atoms_in_body)
  {
    return 0;
  }
  int firstAtom=1;
  char *answ=(char*)malloc(maxRuleSize);
   int curIdx=0;
  do
  {
    int curL=strlen(Atoms_in_body->name);
    int i;
    if(firstAtom)
          firstAtom=0;
    else
        answ[curIdx++]=',';
    for(i=0;i<curL;i++)
    {
     answ[curIdx++]=Atoms_in_body->name[i];
    }
    Atoms_in_body=Atoms_in_body->next;
  }while(Atoms_in_body);
  answ[curIdx++]='.';
  answ[curIdx]='\0';
  return answ;
}




int addToList(struct StringList **L,struct StringList *prev,char *newName,int arity,char* term_list)
{
  if(!(*L))
  {
    *L=(struct StringList*)malloc(sizeof (struct StringList));
    (*L)->name=strdup(newName);
    (*L)->arity=arity;

    (*L)->term_list=term_list;
    (*L)->next=0;

    if(prev)
    {
      prev->next=(*L);
    }
  }
  else addToList(&((*L)->next),(*L),newName,arity,term_list);
  return 0;
}


char* getRuLeName(struct StringList *varList)
{
  /* returns a rule name of the form r[id](V1,..Vn),
     where id is the number of the rule among all the cr-rules,
     and V1..Vn are all the variables included into varList
  */

  char *Name=(char*)malloc(maxRuleSize);
  Name[0]='r';
  sprintf(Name+1,"%d",crRuleIndex);
  crRuleIndex++;
  int curL=strlen(Name);
  int openBracket=0;
  if(varList)
  {
    openBracket=1;
    Name[curL++]='(';
  }
  int firstVar=1;
  while(varList)
  {
    if(!firstVar)Name[curL++]=',';
    firstVar=0;
    int nextL=strlen(varList->name);
    int idx;
    for(idx=0;idx<nextL;idx++)
    {
      Name[curL++]=varList->name[idx];
    }
    varList=varList->next;
  }
  if(openBracket)
  {
    Name[curL++]=')';
  }
  Name[curL]='\0';
  return Name;
}

char *concat2(char *str1,char *str2)   /*concatenate two strings*/
{
    int L=strlen(str1)+strlen(str2);
    char *s=(char*)malloc(L+2);
    sprintf(s,"%s%s",str1,str2);
    free(str1);
    free(str2);
    return s;
}


int getArity(char *name_sequence)
{
  int openBrackets=0;
  int arity=1;
  do
  {
   if(*name_sequence=='(')++openBrackets;
   if(*name_sequence==')')--openBrackets;
   if(*name_sequence==',' && openBrackets++ )++arity;
  }while(*(++name_sequence));
  return arity;
}

int sortDefinition,negativeContext;/*this is for extra condition in SPARC20 30/01/12 paper*/
int predicateContext;/* =true if the parser is  inside a predicate*/
int termHasOperations=0;
int arithmeticTermId;

int stringInList(char *S,StringList*L)
{

/* this function checks whether list L contains string S*/
if(L==0)return 0; /* if the list is empty,there are no variables in it*/
do
{
   if(!strcmp(L->name,S))return 1;
}  while(L=L->next);
return 0;
}

char* checkVariablesSafety(StringList *VarsInPositivePart,StringList *VarsInNegativePart)
{

 if(VarsInNegativePart==0)return 0;

 /* this function checks if all variables of negative part
 (e.g not a_m+1,..not a_n) of a rule in sort definition
 are also included into some atom of a positive part of the rule's body{a1,..a_m}*/
 do
 {
   if(!stringInList(VarsInNegativePart->name,VarsInPositivePart))
   {
      return VarsInNegativePart->name;
   }
 }while(VarsInNegativePart=VarsInNegativePart->next);
 return 0;
}


void CreateProgramRule(char *ruleLabel,char *head,char *sep,char *bodyo)
{
   char ** VarNames=getUniqueVariableNames(Vars,arithmeticTermId);
   char * arithmeticTermsDeclaration=getATermsDeclaration(VarNames,arithmeticTermId);
   clearList(&termsWithOperations);
   char *bodyf=getExpandedBody();
   char* bodyr=unionBodies(bodyf,arithmeticTermsDeclaration);
   if(bodyo)bodyo[strlen(bodyo)-1]='\0';
   char *bodyw=unionBodies(bodyr,bodyo);
   char *body=0;
   char *ruleName=0;
   char *applR=0;
   if(!strcmp(sep,":+"))
   {
     ruleName=getRuLeName(Vars);
     applR=(char*)malloc(strlen(ruleName)+8);
     sprintf(applR,"appl(%s)",ruleName);
     body=unionBodies(bodyw,applR);

   }
   else
   {
     body=strdup(bodyw);
   }
   if(bodyf)free(bodyf);
   if(bodyr)free(bodyr);
   if(body && head)
   {
     char *result=(char*)malloc(strlen(head)+strlen(body)+6);
     sprintf(result,"%s %s %s\n",head,":-",body);
     fprintf(yyout,removeReplacers(result));

   }
   else if(head)
   {
      fprintf(yyout,"%s.\n",removeReplacers(head));

   }
   else fprintf(yyout,"%s %s\n",":-",removeReplacers(body));

   if(!strcmp(sep,":+"))
   {
      fprintf(yyout,":~ %s\n",removeReplacers(body));
      if(bodyw)
      {
         fprintf(yyout,"%s | -%s :- %s\n",applR,applR,removeReplacers(bodyw));
      }
      else
      {
         fprintf(yyout,"%s | -%s.\n",applR,applR);
      }
   }

  /*if(ruleLabel)fprintf(yyout,"belongs_to(%s,%s).\n",ruleLabel,ruleName);
  this is not needed */
  if(applR)free(applR);
  if(ruleName)free(ruleName);
  if(bodyw)free(bodyw);
  if(body)free(body);
 /*clearList(Predicates); we do this when we call getExpandedBody()*/
   clearList(&Vars);
   arithmeticTermId=0;
}
%}
%glr-parser
%error-verbose
%union {
  char *str;
  int intval;
}
/* declare tokens */
%token<intval> SORTDEFKEYWORD
%token<intval> PREDDEFKEYWORD
%token<intval> PROGRULDEFKEYWORD
%token<str> IDENTIFIER
%token<str> IDENTIFIER_WITH_OP
%token<str> VARIABLE
%token<str> POSITIVE_INTEGER
%token<str> NEGATIVE_INTEGER
%token<str> ZERO
%token<str> OP
%token<str> CP
%token<str> ORRSEP
%token<str> CRRSEP
%token<str> COMMA
%token<str> DOT
%token<str> NEGATIVE_ATOM_WITH_OP;
%right<str> EQ
%token<str> NOT
%token<str> COLON
%right<str> NOTEQ
%right<str> GT
%right<str> GTEQ
%right<str> SM
%right<str> SMEQ
%left<str> PLUS MINUS
%left<str> MULT DIV MOD
%type <int> program
%type <str> sortdefs preddefs progrules rule_in_sort_def_sequence
            rule_in_sort_def non_rel_atom  pred_symbol term_sequence
            atom_sequence  arithmetic_term symbolic_function
            symbolic_constant symbolic_term term rel atom
            pred_decl_sequence rule_in_pred_decl symbol_sequence
            rule_in_progrules_sequence rule_in_progrules head body
            var integer extended_non_rel_atom arithmetic_const atomic_term factor
            addop multop semantic_term

%%

program: SORTDEFKEYWORD{sortDefinition=1;negativeContext=0;} sortdefs
         PREDDEFKEYWORD{sortDefinition=0;} preddefs
         PROGRULDEFKEYWORD{ expand_rules=1;} progrules{}
;

sortdefs: {$$="\0"/* empty!*/} |rule_in_sort_def_sequence
;
preddefs: pred_decl_sequence; /* this part cannot be empty! */
progrules:rule_in_progrules_sequence;



rule_in_sort_def_sequence:
 rule_in_sort_def;

rule_in_sort_def_sequence: rule_in_sort_def_sequence rule_in_sort_def
{
  $$=concat2($1,$2);
}
;

pred_decl_sequence:
  rule_in_pred_decl;

pred_decl_sequence:
  pred_decl_sequence rule_in_pred_decl
{
  $$=concat2($1,$2);
}
;
rule_in_pred_decl:
  IDENTIFIER_WITH_OP symbol_sequence CP
{
  char *pred_name=strdup($1);
  pred_name[strlen(pred_name)-1]='\0';/* remove OP */
  int error=addPredicate(pred_name,SplitList($2,1));
  $$=concat2($1,$2);
  if(error)
  {
     yyerror("Multiple declarations of the same predicate");
     YYABORT;
  }
}
;
rule_in_progrules_sequence:
 rule_in_progrules;

rule_in_progrules_sequence: rule_in_progrules_sequence rule_in_progrules
{

  $$=concat2($1,$2);
}
;

rule_in_progrules:
        head DOT
{
  CreateProgramRule(0,$1,":-",0);
  $$=concat2($1,$2);
};



rule_in_progrules:
        head ORRSEP body
{
 CreateProgramRule(0,$1,$2,$3);
 $$=concat3($1,$2,$3);
};


rule_in_progrules:head CRRSEP DOT
{
 CreateProgramRule(0,$1,$2,0);
 $$=concat3($1,$2,$3);
}
;



rule_in_progrules:head CRRSEP body
{
 CreateProgramRule(0,$1,$2,$3);
 $$=concat3($1,$2,$3);
}

rule_in_progrules:IDENTIFIER COLON head CRRSEP DOT
{

 CreateProgramRule($1,$3,$4,0);
 $$=concat3($3,$4,$5);
}
;

rule_in_progrules:IDENTIFIER COLON head CRRSEP body
{
 CreateProgramRule($1,$3,$4,$5);
 $$=concat3($3,$4,$5);
}


;
rule_in_progrules: CRRSEP body
{
 CreateProgramRule(0,0,$1,$2);
 $$=concat2($1,$2);
}
;
;
rule_in_progrules: ORRSEP body
{
 CreateProgramRule(0,0,$1,$2);
 $$=concat2($1,$2);
}
;

rule_in_progrules: IDENTIFIER COLON CRRSEP body
{
 CreateProgramRule($1,0,$3,$4);
 $$=concat2($1,$2);
}
;


integer :POSITIVE_INTEGER |ZERO| MINUS POSITIVE_INTEGER{$$=concat2($1,$2);};
rule_in_progrules: pred_symbol integer DOT DOT integer CP DOT
{
    arithmeticTermId=0;
    $$=concat3(concat3($1,$2,$3),concat3($4,$5,$6) ,$7);
    fprintf(yyout,"%s\n",$$);
}
;
head : non_rel_atom
{
 $$=$1;
};
body : atom_sequence DOT
{
 $$=concat2($1,$2);
}

var:VARIABLE
{
  $$=$1;
  if(expand_rules)
  {
    addToListUniq(&Vars,0,$$);
  }
  if(negativeContext)
  {
     addToListUniq(&VarsInNegativePart,0,$$);
  }
  else
  {
    addToListUniq(&VarsInPositivePart,0,$$);
  }
}
symbol_sequence:IDENTIFIER;
symbol_sequence:symbol_sequence COMMA IDENTIFIER
{
 $$=concat3($1,$2,$3);
}

;



non_rel_atom:

  pred_symbol{predicateContext=1;} term_sequence CP
{
  predicateContext=0;
  if(expand_rules)
  {
   char *pred_name;
   if($1[0]=='-')pred_name=strdup($1+1);
   else pred_name=strdup($1);
   pred_name[strlen(pred_name)-1]='\0';/*remove OP*/
   int arity=getArity($3);
   addToList(&Predicates,0,pred_name,arity,strdup($3));
  }
   $$=concat3($1,$3,$4);
}
;
extended_non_rel_atom:

  NOT{negativeContext=1;} pred_symbol{predicateContext=1;} term_sequence CP
{
  negativeContext=0;
  predicateContext=0;
  if(expand_rules)
  {
   char *pred_name;
   if($3[0]=='-')pred_name=strdup($3+1);
   else pred_name=strdup($3);
   pred_name[strlen(pred_name)-1]='\0';/*remove OP*/
   int arity=getArity($5);

   addToList(&Predicates,0,pred_name,arity,strdup($5));
  }
   char *buf=concat3($3,$5,$6);
   $$=concat2($1,buf);
}
;

rule_in_sort_def: non_rel_atom ORRSEP atom_sequence DOT
{
             $$=concat3($1,$2,$3);

             int l=strlen($$);
             $$[l]='.';
             $$[l+1]='\0';
             char *wrong_variable=checkVariablesSafety(VarsInPositivePart,VarsInNegativePart);
             if(!wrong_variable)
             {
                fprintf(yyout,"%s\n",$$);
                clearList(&VarsInPositivePart);
                clearList(&VarsInNegativePart);
             }
             else
             {
               yyerror("Variable %s in negative part in the body of the rule \n%s\n is not found in its positive part ",wrong_variable,$$);
               YYABORT;

             }
}
 rule_in_sort_def: non_rel_atom DOT
{

            $$=concat2($1,$2);
            char *wrong_variable=checkVariablesSafety(VarsInPositivePart,VarsInNegativePart);
            if(!wrong_variable)
             {
                fprintf(yyout,"%s\n",$$);
                clearList(&VarsInPositivePart);
                clearList(&VarsInNegativePart);
             }
             else
             {
                yyerror("Variable %s in negative part in the body of the rule \n%s\n is not found in its  positive part ",wrong_variable,$$);
                YYABORT;
             }
}
 rule_in_sort_def:  ORRSEP atom_sequence DOT
{

              $$=concat3($1,$2,$3);
              fprintf(yyout,"%s\n",$$);
}
 rule_in_sort_def:  pred_symbol integer DOT DOT integer CP DOT
{

              $$=concat3(concat3($1,$2,$3),concat3($4,$5,$6) ,$7);
              fprintf(yyout,"%s\n",$$);
}
;


addop:
   PLUS
    {
     $$=$1;
     if(predicateContext)termHasOperations=1;
   }
   | MINUS
    {
     $$=$1;
       if(predicateContext)termHasOperations=1;
   }
;

multop:
    MULT
     {
     $$=$1;
       if(predicateContext)termHasOperations=1;
   }
   | MOD
   {
     $$=$1;
       if(predicateContext)termHasOperations=1;
   }
   | DIV
   {
     $$=$1;
      if(predicateContext) termHasOperations=1;
   }
;

arithmetic_const  :
 integer


atomic_term:arithmetic_const |var
;

arithmetic_term  : factor |
         arithmetic_term addop factor {$$=concat3($1,$2,$3);}
;

factor: semantic_term
  | factor multop term { $$ = concat3($1,$2,$3); }
;

semantic_term: atomic_term
 | OP arithmetic_term CP {$$=concat3($1,$2,$3);};
;
symbolic_function  :IDENTIFIER_WITH_OP
;

symbolic_constant  :IDENTIFIER
;

symbolic_term  :
        symbolic_constant  ;
symbolic_term  :    symbolic_function term_sequence CP
                                  {
                                    $$=concat3($1,$2,$3);
                                  }
;

term  :
     symbolic_term  |  arithmetic_term
     {
       // printf("%s %d\n",$$,termHasOperations);
     if(predicateContext && termHasOperations && expand_rules)
     {
       int idStringLength=getDigitsCount(arithmeticTermId);
       char *termReplacer=(char*)malloc(3+idStringLength);
       termReplacer[0]='$';
       sprintf(termReplacer+1,"%d",arithmeticTermId);
       termReplacer[idStringLength+1]='$';
       termReplacer[idStringLength+2]='\0';
       $$=termReplacer;
       addToList(&termsWithOperations,0,$1,0,0);
       arithmeticTermId++;
     }
     else
     {
        $$=$1;

     }
     termHasOperations=0;
     }
;

term_sequence:
     term
;
term_sequence: term COMMA term_sequence
                  {
                       $$=concat3($1,$2,$3);

                  }
;

rel:
     EQ  |  NOTEQ |  GT  |  GTEQ  |  SM  |  SMEQ
;

pred_symbol  :
      IDENTIFIER_WITH_OP | NEGATIVE_ATOM_WITH_OP {$$=$1;}
;


atom :
   non_rel_atom | extended_non_rel_atom ;

atom:  arithmetic_term  rel  arithmetic_term{$$=concat3($1,$2,$3);} |
   symbolic_term  rel  symbolic_term{$$=concat3($1,$2,$3);}|
   var  rel symbolic_term {$$=concat3($1,$2,$3);}|
   symbolic_term rel var {$$=concat3($1,$2,$3);}
;

atom_sequence:
 atom ;
atom_sequence: atom_sequence COMMA atom
{
    $$=concat3($1,$2,$3);
}
;




%%

void main(int argc, char **argv)
 {
    printf("SPARC to DLV translator V1.09\n");
    extern FILE *yyin;

    if(argc > 1) {               /* if first argument is provided,it is input file*/
       if(!(yyin = fopen(argv[1], "r"))) {
        perror(argv[1]);
        return (1);
       }
      if(!(yyout = fopen(getOutputFile(argv[1]), "w"))) {
        perror(argv[1]);
        return (1);
       }
     }
     else
     {
         yyin=stdin; /*otherwise input is standart input*/
         yyout=stdout;
     }
       if(!yyparse())
       {
          printf("program translated\n");
       }
       else
       {
          printf("program has some errors\n");
       }
       return 0;
 }
